package peer.share;

import java.util.BitSet;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;

import peer.tools.ByteIntSwitch;
import peer.tools.ByteShortSwitch;

public class CacheFileInfo {
	LinkedList<Integer> list;
	byte[] bb;
	boolean isChange=false;
	HashMap<Integer, Integer> hm=new HashMap<Integer, Integer>();
	BitSet bitInfo;
	boolean newAdd=false;
	public CacheFileInfo(){
		list = new LinkedList<Integer>();
		bb=new byte[2];
		ByteShortSwitch.toByteArray((short) 0, bb, 0);
		bitInfo=new BitSet();
	}
	public CacheFileInfo(int blockSum){
		bitInfo=new BitSet();
		bb=new byte[10];
		ByteShortSwitch.toByteArray((short) 1, bb, 0);
		ByteIntSwitch.toByteArray(0, bb, 2);
		ByteIntSwitch.toByteArray(blockSum, bb, 6);
		hm.put(0, blockSum);
	}
	public CacheFileInfo(byte[] b){
		list = new LinkedList<Integer>();
		bitInfo=new BitSet();
		bb=b;
		int fragSum=0;
		if(bb.length>=2){
			fragSum=ByteShortSwitch.toShort(bb, 0);
		}
		hm=new HashMap<Integer, Integer>(fragSum);
		if(b.length==2+8*fragSum){
			for(int i=0;i<fragSum;i++){
				int offset=ByteIntSwitch.toInt(bb, 2+i*8);
				int length=ByteIntSwitch.toInt(bb, 2+i*8+4);
				hm.put(offset, length);
				for(int j=0;j<length;j++){
					int blockNum=offset+j;
					bitInfo.set(blockNum);
					//*************
					if(!list.contains(blockNum)){
						list.add(blockNum);
						isChange=true;
					}
					newAdd=true;
				}
			}
		}
	}
	
	public boolean haveNewAdd(){
		return newAdd;
	}
	
	public void cleanNew(){
		newAdd=false;
	}
	
	public boolean containsBlock(int blockNum){
		return bitInfo.get(blockNum);
	}
	
	public void setBlock(int blockNum){
		bitInfo.set(blockNum);
		if(!list.contains(blockNum)){
			list.add(blockNum);
			isChange=true;
		}
	}
	
	public void addBlock(int blockNum){
		bitInfo.set(blockNum);
		if(!list.contains(blockNum)){
			list.add(blockNum);
			isChange=true;
		}
		newAdd=true;
	}
	
	void update(){
		Collections.sort(list);
		hm=new HashMap<Integer, Integer>();
		int off=0;
		int offset=0;
		B: while(true){
			if(off<list.size()){
				offset=list.get(off);
			}else{
				break;
			}
			int length=1;
			C: while(true){
				if(off<list.size()){
					int nowBlock=list.get(off);
					if((off+1)<list.size()){
						int nextBlock=list.get(off+1);
						off++;
						if(nextBlock-nowBlock==1){
							length++;
						}else{
							break C;
						}
					}else{
						off++;
						break C;
					}
				}else{
					break B;
				}
			}
			hm.put(offset, length);
		}
		
		bb=new byte[2+hm.size()*8];
		ByteShortSwitch.toByteArray((short) hm.size(), bb, 0);
		Iterator<Integer> it=hm.keySet().iterator();
		for(int i=0;i<hm.size();i++){
			int offset2=it.next();
			int length2=hm.get(offset2);
			ByteIntSwitch.toByteArray(offset2, bb, 2+i*8);
			ByteIntSwitch.toByteArray(length2, bb, 2+i*8+4);
		}
		isChange=false;
	
	}
	
	public byte[] getByte(){
		if(isChange){
			update();
		}
		return bb;
	}
	
	public HashMap<Integer, Integer> getHm(){
		if(isChange){
			update();
		}
		return hm;
	}
}

